package util;
import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInput;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.net.InetAddress;
import java.net.Socket;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.text.DecimalFormat;
import java.util.*;

import javax.swing.DefaultListModel;
import javax.swing.JOptionPane;
import javax.swing.table.DefaultTableModel;
import javax.swing.tree.DefaultMutableTreeNode;

import com.sun.corba.se.spi.orbutil.fsm.Input;

import mill.*;
import mill.components.MillComponent;
import mill.measurePoints.MeasurePoint;


public class Model implements Serializable{

	private List<MillPark> m_parks;
	private List<MillLog> m_logs;
	private MillPark m_selectedPark;

	private String serverAdr;
	private int port_no;
	private boolean close = false;

	StartDialog dialog;

	public Model() {
		dialog = new StartDialog();
		updateFromServer();
	}

	public boolean isThisClose()
	{
		return close;
	}

	public void changeSelected(MillPark park){
		m_selectedPark = park;
	}

	public List<MillPark> get_MillParks()
	{
		return m_parks;
	}

	public int findMillParkIndex(MillPark park)
	{
		return m_parks.indexOf(park);
	}

	public DefaultTableModel get_TableModel(int index)
	{
		DefaultTableModel m_mainTable = new DefaultTableModel();

		m_mainTable.addColumn("Mill id");
		m_mainTable.addColumn("Output");
		m_mainTable.addColumn("Type");
		m_mainTable.addColumn("Height");
		m_mainTable.addColumn("Wingspan");
		m_mainTable.addColumn("Status");

		Object[] data = new Object[6];

		for(IMill mill : m_parks.get(index).getMills())
		{
			data[0] = "" + mill.getSerialNumber();
			data[1] = "" + mill.getPowerOutput() + " W";
			data[2] = "" + mill.getType().toString();
			data[3] = "" + mill.getHeight() + "m";
			data[4] = "" + mill.getWingSpan() + "m";
			data[5] = "" + mill.getStatus().toString();

			m_mainTable.addRow(data);
		}

		return m_mainTable;
	}

	public DefaultTableModel get_TableModelForLog()
	{
		DefaultTableModel m_mainTable = new DefaultTableModel();
		Object[] data = new Object[6];

		m_mainTable.addColumn("Mill id");
		m_mainTable.addColumn("airTemperature");
		m_mainTable.addColumn("windDirection");
		m_mainTable.addColumn("windSpeed");
		m_mainTable.addColumn("powerOutput");
		m_mainTable.addColumn("timeStamp");

		DecimalFormat twoPlaces = new DecimalFormat("0.00");

		for(MillLog log : m_logs)
		{
			data[0] = "" + log.getSerialNumber();
			data[1] = "" + twoPlaces.format(log.getAirTemperature());
			data[2] = "" + log.getWindDirection();
			data[3] = "" + log.getWindSpeed();
			data[4] = "" + log.getPowerOutput();
			data[5] = "" + log.getTimeStamp();

			m_mainTable.addRow(data);
		}

		return m_mainTable;
	}

	public DefaultMutableTreeNode get_TreeModel()
	{
		DefaultMutableTreeNode top = new DefaultMutableTreeNode("Mill Parks");

		createTreeNodes(top);

		return top;
	}

	private void createTreeNodes(DefaultMutableTreeNode top)
	{
		DefaultMutableTreeNode parks = null;
		DefaultMutableTreeNode mills = null;
		DefaultMutableTreeNode components = null; 
		DefaultMutableTreeNode measurePoints = null;  
		DefaultMutableTreeNode componentsContainer = null;
		DefaultMutableTreeNode mpointsContainer = null;

		for(MillPark millPark : m_parks)
		{
			parks = new DefaultMutableTreeNode(millPark);
			top.add(parks);

			for(IMill mill : millPark.getMills())
			{
				mills = new DefaultMutableTreeNode(mill);
				parks.add(mills);

				components = new DefaultMutableTreeNode("Components");

				for(MillComponent mc : mill.getComponents())
				{
					componentsContainer = new DefaultMutableTreeNode(mc);
					components.add(componentsContainer);
				}
				componentsContainer = new DefaultMutableTreeNode("New Component");
				components.add(componentsContainer);
				mills.add(components);


				measurePoints = new DefaultMutableTreeNode("Measure Points");
				for(MeasurePoint mp : mill.getMeasurePoints())
				{
					mpointsContainer = new DefaultMutableTreeNode(mp);
					measurePoints.add(mpointsContainer);
				}
				mpointsContainer = new DefaultMutableTreeNode("New Measure Point");
				measurePoints.add(mpointsContainer);
				mills.add(measurePoints);
			}

			mills = new DefaultMutableTreeNode("New Windmill");
			parks.add(mills);


		}
		parks = new DefaultMutableTreeNode("New Mill Park");
		top.add(parks);

	}

	public void updateFromServer()
	{
		try
		{
			dialog.showDialog();
			
			close = dialog.isClosePressed();
			serverAdr = dialog.getServerAdr();
			port_no = dialog.getPortNo();
			
			if(!close)
			{
				

				// Create a socket to connect to the server
				Socket connectToServer = new Socket(serverAdr, port_no);

				// Find the Servers' hostname, and IP address
				InetAddress serverInetAddress = connectToServer.getInetAddress();
				System.out.println("Servers hostname is " + serverInetAddress.getHostName());
				System.out.println("Servers  IP Address is " + serverInetAddress.getHostAddress());

				// Create an input Object stream to receive MillPark objects data from the server
				ObjectInputStream clientInputStreamMP = new ObjectInputStream(connectToServer.getInputStream());

				try {
					m_parks = (List<MillPark>)clientInputStreamMP.readObject();

					//clientInputStreamMP.close();
				} catch (ClassNotFoundException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}

				// Create an input Object stream to receive MillLog objects data from the server
				ObjectInputStream clientInputStreamML = new ObjectInputStream(connectToServer.getInputStream());
				try {
					m_logs = (List<MillLog>)clientInputStreamML.readObject();


				} catch (ClassNotFoundException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		}
		catch (IOException ex)
		{
			JOptionPane.showMessageDialog(null,
					"Could not connect to server.",
					"Inane error",
					JOptionPane.ERROR_MESSAGE);


			updateFromServer();
		}

	}

}
